#include "FoGGEDEF.h"
#include <stdio.h>

#include "BugSlayer/Include/BugslayerUtil.h"

namespace _FOGGE_
{


	namespace _GO_
	{
		_UTIL_::Logger * g_ptrLogger=NULL;
	}

	namespace _UTIL_
	{
		Logger::eLogLevel Logger::g_eCurrentLoggingLevel=Logger::eLL_Develop;

		
		enum CONST_BufferSize
		{
			BUFFER_SIZE=32000
		};

		TCHAR g_BigBuffer[BUFFER_SIZE];

		Logger::Logger(eLogLevel level,Name name)
		{
			m_ptrLogChain=NULL;
			m_eLoggingLevel = level;
			m_nameName=name;
			m_ptrTerminal=NULL;
		}

		/*virtual*/
		Logger::~Logger()
		{
			foDELETE(m_ptrTerminal);
			RemoveLoggerAtChain();
		}
	

		void Logger::Format(eLogLevel level, Name& name,LPCTSTR fmt, ... )
		{

			if(m_eLoggingLevel > g_eCurrentLoggingLevel)
				return;//skip this log
			int		len;
			va_list		argptr;
			
			va_start (argptr,fmt);

			len = vsprintf_s(g_BigBuffer,BUFFER_SIZE,fmt,argptr);
				  
			va_end (argptr);


		
			Write(level,name,g_BigBuffer);

			*g_BigBuffer=0;


		}
		void Logger::WriteLine(eLogLevel level,Name& name,LPCTSTR str )
		{
			if(m_eLoggingLevel  > g_eCurrentLoggingLevel)
				return;//skip this log

			_stprintf_s(g_BigBuffer,__T("%s\n"),str);

			Write(level,name,g_BigBuffer);

			*g_BigBuffer=0;


		}

		void Logger::Write(eLogLevel level,Name& name,LPCTSTR str )
		{
			if(m_eLoggingLevel  > g_eCurrentLoggingLevel)
				return;//skip this log

			if(name==Name_None)
			{//
				if(m_eLoggingLevel>=level)
					m_ptrTerminal->Write(g_BigBuffer);
			}
			else	
			{//check the target is me
				if(m_nameName==name)
					m_ptrTerminal->Write(g_BigBuffer);

			}

			
			if(m_ptrLogChain)
				m_ptrLogChain->Write(level,name,str);

		}
		void Logger::Flush()
		{
			m_ptrTerminal->Flush();

			if(m_ptrLogChain)
				m_ptrLogChain->Flush();
		}

		//! attach logger to end of logchain
		void Logger::AttachLoggerToChain(Logger* ptrLogger)
		{
			assert(ptrLogger->m_ptrLogChain==NULL&&"AttachLoggerToChain_ cant attach non-terminal logger");
			if(m_ptrLogChain)
				m_ptrLogChain->AttachLoggerToChain(ptrLogger);
			else
				m_ptrLogChain= ptrLogger;
		}

		//! attach logger to end of logchain
		void Logger::RemoveLoggerAtChain()
		{
			if(m_ptrLogChain)
			{
				m_ptrLogChain->RemoveLoggerAtChain();
				foDELETE(m_ptrLogChain);
			}
			
				
		}

		

		void Logger::AttachTerminal(aTerminal* ptrTerm)
		{
			if(m_ptrTerminal)
				m_ptrTerminal->AttachTerminalToChain(ptrTerm);
			else
				m_ptrTerminal = ptrTerm;
		}




		namespace _HELPER_
		{
	
			LONG RetrieveCallStack ( EXCEPTION_POINTERS * pExPtrs ,foUInt level,Name name)
			{
				static foString strCall_Stack;

				strCall_Stack.clear();

				strCall_Stack+= __T("=>@@@@@Call Stack@@@@@@\n");

				
				LPCTSTR szBuff = GetFirstStackTraceString ( /*GSTSO_PARAMS*/0x01 | /*GSTSO_MODULE*/0x02 | /*GSTSO_SYMBOL*/0x04 | /*GSTSO_SRCLINE*/0x08  ,	pExPtrs  ) ;
				do
				{
					strCall_Stack+=szBuff ;
					strCall_Stack+=__T("\n");
					szBuff = GetNextStackTraceString ( /*GSTSO_PARAMS*/0x01 | /*GSTSO_MODULE*/0x02 | /*GSTSO_SYMBOL*/0x04 | /*GSTSO_SRCLINE*/0x08, pExPtrs ) ;


				}
				while ( NULL != szBuff ) ;
			
				strCall_Stack+= __T("<=@@@@@Call Stack@@@@@@\n");


				::_FOGGE_::_GO_::g_ptrLogger->WriteLine((_FOGGE_::_UTIL_::Logger::eLogLevel)level,name,strCall_Stack.c_str());

				return ( EXCEPTION_EXECUTE_HANDLER ) ;
			}
		}
	}
}